MOOC Utils

Utils like auto assignment solver extension and course notice announcment notification for MOOC courses

API reference

Introduction#

Notice Reminders exposes a REST API for auth, course search, announcements, subscriptions, and user profiles. Each endpoint below lists method, path, schemas, auth rules, and example payloads. The website client and the usual security notes (cookies, JWT, rate limits) live here too.

Project structure#

The API is implemented as a FastAPI application with modular routers grouped by domain. The website’s Next.js frontend consumes the API through a dedicated client that manages cookies and handles errors.

Core components#

  • Authentication and Authorization
  • Access tokens are validated via a dependency that reads the access_token cookie and verifies JWT claims.
  • Decorators enforce authentication for protected endpoints.
  • Cookie-Based Session Management
  • Login and refresh set httponly cookies for access_token and refresh_token with appropriate expiration and security attributes.
  • CORS
  • Cross-origin requests are permitted from configured origins with credentials allowed.
  • Settings
  • Token expirations, cache TTL, and external service URLs are configurable.

Architecture overview#

The API follows a layered architecture:

  • Routers define endpoints and bind request/response schemas.
  • Services encapsulate business logic.
  • Models and schemas define data contracts.
  • Authentication middleware and decorators protect endpoints.
  • The website client communicates over HTTPS with cookie-based sessions.

Detailed component analysis#

Authentication endpoints#

  • Base Path: /auth
  • Authentication Requirement:
  • request-otp: Not authenticated.
  • verify-otp, refresh, logout, me: Requires access token via cookie.

Endpoints:

  • POST /auth/request-otp

  • Description: Requests an OTP for the given email. Returns whether the user is new and expiry time.

  • Authentication: Not required.

  • Request Body: OtpRequest

  • email: string (Email)

  • Response: OtpRequestResponse

  • message: string

  • is_new_user: boolean

  • expires_at: datetime (ISO 8601)

  • Example Request:

  • POST /auth/request-otp with JSON {“email":"[email protected]”}

  • Example Response:

  • 200 OK {“message”:“OTP sent”,“is_new_user”:true,“expires_at”:“2025-01-01T12:00:00Z”}

  • POST /auth/verify-otp

  • Description: Verifies OTP and creates access and refresh tokens, setting cookies.

  • Authentication: Not required.

  • Request Body: OtpVerify

  • email: string (Email)

  • code: string

  • Response: AuthStatus

  • user: UserResponse

  • is_new_user: boolean

  • Cookies Set:

  • access_token: httponly, sameSite lax, path “/”, secure unless debug

  • refresh_token: httponly, sameSite lax, path “/”, secure unless debug

  • Example Request:

  • POST /auth/verify-otp with JSON {“email":"[email protected]”,“code”:“123456”}

  • Example Response:

  • 200 OK {“user”:{“id":1,“email”:"[email protected]”…},“is_new_user”:false}

  • POST /auth/refresh

  • Description: Refreshes access token using a valid refresh token cookie.

  • Authentication: Not required (uses refresh cookie).

  • Response: AuthStatus

  • Cookies Updated: Sets new access_token and refresh_token.

  • Example Request:

  • POST /auth/refresh with cookies containing refresh_token

  • Example Response:

  • 200 OK {“user”:{“id”:1…},“is_new_user”:false}

  • POST /auth/logout

  • Description: Revokes refresh token and deletes cookies.

  • Authentication: Not required (reads refresh cookie).

  • Response: 204 No Content

  • Example Request:

  • POST /auth/logout with cookies containing refresh_token

  • Example Response:

  • 204 No Content

  • GET /auth/me

  • Description: Returns currently authenticated user.

  • Authentication: Required (access token cookie).

  • Response: UserResponse

  • Example Request:

  • GET /auth/me with access_token cookie

  • Example Response:

  • 200 OK {“id":1,“email”:"[email protected]”…}

Schemas:

  • OtpRequest: email (EmailStr)
  • OtpVerify: email (EmailStr), code (str)
  • OtpRequestResponse: message (str), is_new_user (bool), expires_at (datetime)
  • AuthStatus: user (UserResponse), is_new_user (bool)

Security Notes:

  • Access and refresh tokens are stored as httponly cookies with SameSite lax and path “/”.
  • Secure flag is enabled unless debug is true.
  • Access token expiration and refresh token expiration are configured in settings.

Course endpoints#

  • Base Path: /courses
  • Authentication: Not required for listing and retrieving by code.

Endpoints: - GET /courses

  • Description: Lists all courses.

  • Response: array of CourseResponse

  • Example Request:

  • GET /courses

  • Example Response:

  • 200 OK [{“id”:1,“code”:“CS101”…}…]

  • GET /courses/{course_code}

  • Description: Retrieves a course by its code.

  • Path Parameters:

  • course_code: string

  • Response: CourseResponse

  • Errors:

  • 404 Not Found if course does not exist

  • Example Request:

  • GET /courses/CS101

  • Example Response:

  • 200 OK {“id”:1,“code”:“CS101”,“title”:“Intro to CS”…}

Schemas:

  • CourseResponse: id (int), code (str), title (str), url (str), instructor (str), institute (str), nc_code (str), created_at (datetime), updated_at (datetime)

Course search endpoint#

  • Base Path: /search
    • Authentication: Not required.

Endpoints:

  • GET /search?q={query}
  • Description: Searches courses by query string and caches results.
  • Query Parameters:
  • q: string (required)
  • Response: array of CourseResponse
  • Example Request:
  • GET /search?q=computer
  • Example Response:
  • 200 OK [{“id”:1,“code”:“CS101”…}…]

Course announcement retrieval#

  • Base Path: /courses/{course_code}/announcements
  • Authentication: Required.

Endpoints:

  • GET /courses/{course_code}/announcements
  • Description: Fetches and caches announcements for a course.
  • Path Parameters:
  • course_code: string
  • Response: array of AnnouncementResponse
  • Errors:
  • 404 Not Found if course does not exist
  • Example Request:
  • GET /courses/CS101/announcements with access_token cookie
  • Example Response:
  • 200 OK [{“id”:1,“course_id”:1,“title”:“Welcome”…}…]

Schemas:

  • AnnouncementResponse: id (int), course_id (int), title (str), date (str), content (str), fetched_at (datetime)

Subscription management#

  • Base Path: /subscriptions
  • Authentication: Required.

Endpoints:

  • POST /subscriptions

  • Description: Creates a subscription for the authenticated user to a course.

  • Request Body: SubscriptionCreate

  • course_code: string

  • Response: SubscriptionResponse

  • Errors:

  • 404 Not Found if course does not exist

  • Status Codes:

  • 201 Created on success

  • Example Request:

  • POST /subscriptions with {“course_code”:“CS101”} and access_token cookie

  • Example Response:

  • 201 Created {“id”:1,“user_id”:1,“course_id”:1,“is_active”:true…}

  • GET /subscriptions

  • Description: Lists subscriptions for the authenticated user.

  • Response: array of SubscriptionResponse

  • Example Request:

  • GET /subscriptions with access_token cookie

  • Example Response:

  • 200 OK [{“id”:1,“user_id”:1,“course_id”:1,“is_active”:true}…]

  • DELETE /subscriptions/{subscription_id}

  • Description: Deletes a subscription owned by the authenticated user.

  • Path Parameters:

  • subscription_id: integer

  • Errors:

  • 404 Not Found if subscription does not exist

  • 403 Forbidden if subscription does not belong to the user

  • Status Codes:

  • 204 No Content on success

  • Example Request:

  • DELETE /subscriptions/1 with access_token cookie

  • Example Response:

  • 204 No Content

Schemas:

  • SubscriptionCreate: course_code (string)
  • SubscriptionResponse: id (int), user_id (int), course_id (int), is_active (boolean), created_at (string)

User profile and channels#

  • Base Path: /users
  • Authentication: Required for all user endpoints.

Endpoints:

  • GET /users/{user_id}

  • Description: Retrieves a user by ID.

  • Path Parameters:

  • user_id: integer

  • Errors:

  • 403 Forbidden if requesting another user’s data

  • 404 Not Found if user does not exist

  • Response: UserResponse

  • Example Request:

  • GET /users/1 with access_token cookie

  • Example Response:

  • 200 OK {“id":1,“email”:"[email protected]”…}

  • PATCH /users/{user_id}

  • Description: Updates user profile fields.

  • Path Parameters:

  • user_id: integer

  • Request Body: UserUpdate

  • email?: string

  • name?: string

  • telegram_id?: string

  • is_active?: boolean

  • Errors:

  • 403 Forbidden if updating another user’s data

  • 404 Not Found if user does not exist

  • Response: UserResponse

  • Example Request:

  • PATCH /users/1 with {“name”:“Updated Name”} and access_token cookie

  • Example Response:

  • 200 OK {“id":1,“email”:"[email protected]”,“name”:“Updated Name”…}

  • DELETE /users/{user_id}

  • Description: Deletes the user account.

  • Path Parameters:

  • user_id: integer

  • Errors:

  • 403 Forbidden if deleting another user’s account

  • 404 Not Found if user does not exist

  • Status Codes:

  • 204 No Content

  • Example Request:

  • DELETE /users/1 with access_token cookie

  • Example Response:

  • 204 No Content

  • POST /users/{user_id}/channels

  • Description: Adds a notification channel for the user.

  • Path Parameters:

  • user_id: integer

  • Request Body: NotificationChannelCreate

  • channel: “email” | “telegram”

  • address: string (required for telegram)

  • is_active?: boolean

  • Errors:

  • 403 Forbidden if acting on another user

  • 400 Bad Request if telegram channel lacks address

  • 404 Not Found if user does not exist

  • Response: NotificationChannelResponse

  • Example Request:

  • POST /users/1/channels with {“channel”:“telegram”,“address”:“123456789”} and access_token cookie

  • Example Response:

  • 201 Created {“id”:1,“user_id”:1,“channel”:“telegram”,“address”:“123456789”…}

  • GET /users/{user_id}/channels

  • Description: Lists notification channels for the user.

  • Path Parameters:

  • user_id: integer

  • Errors:

  • 403 Forbidden if listing another user’s channels

  • 404 Not Found if user does not exist

  • Response: array of NotificationChannelResponse

  • Example Request:

  • GET /users/1/channels with access_token cookie

  • Example Response:

  • 200 OK [{“id”:1,“user_id”:1,“channel”:“telegram”,“address”:“123456789”}…]

Schemas:

  • UserUpdate: email (EmailStr?), name (string?), telegram_id (string?), is_active (boolean?)
  • UserResponse: id (int), email (EmailStr), name (string?), telegram_id (string?), is_active (boolean), created_at (datetime), updated_at (datetime)
  • NotificationChannelCreate: channel (“email”|“telegram”), address (string), is_active (boolean?)
  • NotificationChannelResponse: id (int), user_id (int), channel (“email”|“telegram”), address (string), is_active (boolean), created_at (string)

Notifications#

  • Base Path: /notifications
  • Authentication: Required.

Endpoints:

  • GET /notifications

  • Description: Lists notifications for the authenticated user.

  • Response: array of NotificationResponse

  • Example Request:

  • GET /notifications with access_token cookie

  • Example Response:

  • 200 OK [{“id”:1,“user_id”:1,“subscription_id”:1,“announcement_id”:1,“channel_id”:null…}…]

  • GET /notifications/users/{user_id}

  • Description: Lists notifications for a specific user (self-only).

  • Path Parameters:

  • user_id: integer

  • Errors:

  • 403 Forbidden if accessing another user’s notifications

  • Response: array of NotificationResponse

  • Example Request:

  • GET /notifications/users/1 with access_token cookie

  • Example Response:

  • 200 OK […]

  • PATCH /notifications/{notification_id}/read

  • Description: Marks a notification as read for its owner.

  • Path Parameters:

  • notification_id: integer

  • Errors:

  • 404 Not Found if notification does not exist

  • 403 Forbidden if notification does not belong to the user

  • Response: NotificationResponse

  • Example Request:

  • PATCH /notifications/1/read with access_token cookie

  • Example Response:

  • 200 OK {“id”:1,“user_id”:1,“is_read”:true…}

Schemas:

  • NotificationResponse: id (int), user_id (int), subscription_id (int), announcement_id (int), channel_id (int|null), sent_at (string), is_read (boolean)

Dependency analysis#

The API is composed of loosely coupled routers, each depending on services and schemas. Authentication is centralized via a dependency that validates access tokens and enforces protection via decorators.

Performance considerations#

  • Caching
  • Course search and announcement retrieval are cached with a configurable TTL to reduce repeated scraping and database load.
  • Token Expirations
  • Access tokens expire after a short period; refresh tokens rotate periodically to balance security and UX.
  • Database Initialization
  • In debug mode, schemas are generated automatically to aid development.

Recommendations:

  • Prefer batch operations where possible (listing subscriptions, notifications).
  • Use pagination if lists grow large.
  • Monitor cache hit rates for search and announcements.

Troubleshooting guide#

Common Errors and Causes:

  • 401 Unauthorized
  • Missing or invalid access_token cookie.
  • Expired access token.
  • 403 Forbidden
  • Attempting to access another user’s data or resources.
  • 404 Not Found
  • Resource does not exist (course, subscription, notification).
  • 400 Bad Request
  • Validation errors (e.g., missing telegram address when adding channel).

Frontend Client Behavior:

  • The client sends credentials with each request and throws a typed error on non-OK responses.
  • 204 No Content responses are handled explicitly.

Conclusion#

Auth, courses, announcements, subscriptions, and profile routes share cookie sessions and ownership checks. Wire the website client with credentials included and treat 401/403 as a signal to refresh or re-login.

Appendices#

API client implementation details#

  • Base URL
  • Determined by NEXT_PUBLIC_API_URL environment variable; defaults to http://localhost:8000.
  • Credentials
  • credentials: “include” so cookies are sent and received.
  • Error Handling
  • Non-OK responses raise a typed APIError with status and message.
  • 204 No Content is supported and returns undefined.

Key Functions:

  • Authentication: requestOtp, verifyOtp, refreshSession, logout, getMe
  • Users: getUser, updateUser, deleteUser, addNotificationChannel, listUserChannels
  • Courses: listCourses, getCourse, searchCourses
  • Announcements: listAnnouncements
  • Subscriptions: createSubscription, listSubscriptions, deleteSubscription
  • Notifications: listNotifications, markNotificationRead

Security and rate limiting considerations#

  • Cookies
  • access_token and refresh_token are httponly, with secure flag based on debug mode, sameSite lax, and path “/”.
  • CORS
  • Origins are configurable; credentials are allowed.
  • Token Lifetimes
  • Access token and refresh token expirations are configurable.
  • Rate Limiting
  • Not implemented at the API level in the provided code. Consider adding rate limiting at the gateway or middleware if needed.